﻿namespace dotnet_notes.Extensions
{
    /// <summary>
    /// 枚举扩展类
    /// </summary>
    public static class EnumExtension
    {
        #region 基础信息

        /// <summary>
        /// 获取枚举元素的 int 值
        /// </summary>
        public static int GetInt(this Enum input)
        { 
            return Convert.ToInt32(input);
        }

        /// <summary>
        /// 获取枚举元素的 Description 特性描述
        /// </summary>
        public static string GetDescription(this Enum input)
        {
            return input.GetType()
                .GetField(input.ToString())
                ?.GetCustomAttribute<DescriptionAttribute>()?.Description ?? "";
        }

        /// <summary>
        /// 根据 Type 获取枚举全部信息
        /// </summary>
        /// <param name="enumType">枚举 Type</param>
        /// <returns></returns>
        public static List<EnumInfo> GetEnumInfos(this Type enumType)
        {
            if (!enumType.IsEnum)
            {
                throw new ArgumentException($"参数 {nameof(enumType)} 是无效的枚举类型");
            }

            var infos = new List<EnumInfo>();

            foreach (Enum item in Enum.GetValues(enumType))
            {
                var info = new EnumInfo
                {
                    Name = item.ToString(),
                    Value = item.GetInt(),
                    Describe = item.GetDescription()
                };

                infos.Add(info);
            }

            return infos;
        }

        #endregion

        #region 流程控制

        /// <summary>
        /// 获取下一个枚举值(枚举元素需要设置顺序特性值)
        /// </summary>
        public static int? NextValue(this Enum input)
        {
            var infos = input.GetType().GetSerialInfos();
            int? inputSerialNumber = input.GetSerialNumber();

            return infos.OrderBy(x => x.SerialNumber)
                .Where(x => x.SerialNumber > inputSerialNumber)
                .FirstOrDefault()?.Value;
        }

        /// <summary>
        /// 获取上一个枚举值(枚举元素需要设置顺序特性值)
        /// </summary>
        public static int? PreviousValue(this Enum input)
        {
            var infos = input.GetType().GetSerialInfos();
            int? inputSerialNumber = input.GetSerialNumber();

            return infos.OrderByDescending(x => x.SerialNumber)
                .Where(x => x.SerialNumber < inputSerialNumber)
                .FirstOrDefault()?.Value;
        }

        /// <summary>
        /// 获取枚举所有元素的顺序信息
        /// </summary>
        public static List<EnumSerialInfo> GetSerialInfos(this Type type)
        {
            if (!type.IsEnum)
            {
                throw new ArgumentException($"参数 {nameof(type)} 是无效的枚举类型");
            }

            var infos = new List<EnumSerialInfo>();

            foreach (Enum item in Enum.GetValues(type))
            {
                infos.Add(new EnumSerialInfo
                {
                    SerialNumber = item.GetSerialNumber()
                        ?? throw new InvalidOperationException("所有枚举元素需要设置顺序编号"),

                    Value = item.GetInt()
                });
            }

            return infos;
        }

        /// <summary>
        /// 获取枚举元素对应的顺序特性值
        /// </summary>
        public static int? GetSerialNumber(this Enum input)
        {
            return input.GetType()
                .GetField(input.ToString())
                ?.GetCustomAttribute<EnumSerialAttribute>()?.Value;
        }

        #endregion
    }
}
